<template>
  <div class="webssh-container">
    <div
        ref="terminal"
        :id="tabId"
        v-loading="loading"
        class="terminal-container"
        element-loading-text="拼命连接中"
    ></div>
  </div>

  <ScriptsDialog :dialog-visible="ScriptsDialogVisible"
                 @close="handleCloseScriptsDialog"
                 @execute="handleExecuteCommand"
                 @update:dialogVisible="ScriptsDialogVisible = $event"/>

</template>


<script lang="ts" setup>
import {ref, onBeforeUnmount, onMounted, nextTick} from 'vue'
import {Terminal} from 'xterm'
import {FitAddon} from 'xterm-addon-fit'
import {WebLinksAddon} from 'xterm-addon-web-links'
import {SearchAddon} from 'xterm-addon-search'
import 'xterm/css/xterm.css'
import {type ConnectServerInfo} from "@/type/webShell/connectServerInfo";
import {defineProps} from "vue";
import {message} from "@/utils/ElmessasgeUtils";
import ScriptsDialog from '@/views/webShell/Dialog/ScriptsPlaneDialog.vue'


const terminal = ref<Terminal>()
const fitAddon = ref<FitAddon>()

let loading = ref(false)
let terminalSocket = ref()
let term = ref()
let resizeTimer: any = null
let lastSize = {cols: 0, rows: 0}

const ScriptsDialogVisible = ref(false)

const handleOpenScriptsDialog = () => {
  ScriptsDialogVisible.value = true
}


const handleCloseScriptsDialog = () => {
  ScriptsDialogVisible.value = false
}

interface Props {
  formData: ConnectServerInfo;
}

const props = defineProps<Props>();

const isConnecting = ref(false)

const generateId = () => {
  return Date.now().toString(36) + Math.random().toString(36).substring(2)
}

const tabId = generateId()

// 自定义处理函数
const handleCtrlDoubleClick = () => {
  handleOpenScriptsDialog()
}

//  ------ 初始化XTerm ------
const initTerminal = () => {

  const terminalContainer = document.getElementById(tabId)
  if (!terminalContainer) return

  // 清除可能存在的旧终端
  terminalContainer.innerHTML = ''

  term.value = new Terminal({
    fontSize: 14,
    fontFamily: 'Consolas, "Courier New", monospace',
    theme: {
      background: '#151010',
      foreground: '#F0F0F0',
      cursor: '#A0A0A0',
      selection: '#3A3D41',
      black: '#1E1E1E',
      red: '#F44747',
      green: '#608B4E',
      yellow: '#DCDCAA',
      blue: '#569CD6',
      magenta: '#C586C0',
      cyan: '#4EC9B0',
      white: '#D4D4D4',
      brightBlack: '#808080',
      brightRed: '#F44747',
      brightGreen: '#608B4E',
      brightYellow: '#DCDCAA',
      brightBlue: '#569CD6',
      brightMagenta: '#C586C0',
      brightCyan: '#4EC9B0',
      brightWhite: '#FFFFFF'
    },
    cursorBlink: true,
    convertEol: true,
    disableStdin: false
  })

  fitAddon.value = new FitAddon();
  term.value.loadAddon(fitAddon.value)
  term.value.loadAddon(new WebLinksAddon())
  term.value.loadAddon(new SearchAddon())
  term.value.open(terminal.value) //挂载dom窗口

  // 换行并输入起始符“$”
  term.value.prompt = () => {
    term.value.write("\r\n$ ");
  };


  // 获取终端元素并添加双击事件监听器
  const terminalElement = document.getElementById(tabId)
  if (terminalElement) {
    const xtermScreen = terminalElement.querySelector('.xterm-screen')
    if (xtermScreen) {
      xtermScreen.addEventListener('dblclick', (e: MouseEvent) => {
        e.preventDefault()
        e.stopPropagation()
        handleCtrlDoubleClick()
      })
    }
  }

  //Terminal 键盘输入事件挂载
  term.value.onData((data: any) => {
    if (isWsOpen()) {
      terminalSocket.value.send(
          JSON.stringify({
            operate: 'command',
            command: data
          })
      )
    }
  })

  // 监听窗口大小变化，但添加防抖和大小比较，避免Tab切换时的抖动
  term.value.onResize((size: any) => {
    // 检查终端容器是否可见（Tab切换时的处理）
    const container = document.getElementById(tabId)
    const isVisible = container && container.offsetParent !== null

    // 只有在容器可见且大小确实发生变化时才处理
    if (isVisible && (size.cols !== lastSize.cols || size.rows !== lastSize.rows)) {
      // 清除之前的定时器
      if (resizeTimer) clearTimeout(resizeTimer)

      // 设置新的定时器（防抖）
      resizeTimer = setTimeout(() => {
        if (terminalSocket.value?.readyState === WebSocket.OPEN) {
          terminalSocket.value.send(JSON.stringify({
            operate: 'resize',
            cols: size.cols,
            rows: size.rows
          }))
        }
        // 更新最后记录的大小
        lastSize.cols = size.cols
        lastSize.rows = size.rows
      }, 100) // 100ms防抖延迟
    }
  })

  setTimeout(() => {
    fitAddon.value?.fit()
  }, 100)

  // 添加窗口大小变化监听器
  const resizeObserver = new ResizeObserver(() => {
    fitAddon.value?.fit()
  })

  const container = document.getElementById(tabId)
  if (container) {
    resizeObserver.observe(container)
  }

}

const connect = async () => {

  isConnecting.value = true

  await nextTick()
  initTerminal()

  // 初始化WebSocket
  if (!terminalSocket.value || (terminalSocket.value && terminalSocket.value.readyState > 1)) {
    terminalSocket.value = new WebSocket('ws://' + location.host + '/WebShell/socket/webShell-connect');

    terminalSocket.value.onopen = () => {
      term.value.write('Connecting ' + props.formData.serverIp +
          ':' + props.formData.port + ' as ' + props.formData.serverUsername + '\r\n');

      terminalSocket.value.send(
          JSON.stringify({
            operate: 'connect',
            host: props.formData.serverIp,
            port: props.formData.port,
            username: props.formData.serverUsername,
            password: props.formData.serverPassword,
          }))

      term.value.write('\r\n\x1b[1;3;33m正在连接到服务器...\x1b[0m\r\n')
    }

    terminalSocket.value.onmessage = (message: any) => {
      term.value.write(message.data);
    }

    terminalSocket.value.onclose = () => {
      term.value?.write('\r\n\x1b[1;3;31m连接已关闭\x1b[0m\r\n')
      isConnecting.value = false
    }
    terminalSocket.value.onerror = (error: any) => {
      term.value?.write(`\r\n\x1b[1;3;31m连接错误: ${error}\x1b[0m\r\n`)
      isConnecting.value = false
    }
  }
}

// 处理执行命令
const handleExecuteCommand = (command: string, execFlag: boolean) => {
  if (isWsOpen()) {
    // 发送命令到终端
    terminalSocket.value.send(
        JSON.stringify({
          operate: 'command',
          command: command + (execFlag ? ' \r ' : '')
        })
    )
  } else {
    message('终端未连接，无法执行命令', 'warning')
  }
}
// 是否连接中0 1 2 3 状态
const isWsOpen = () => {
  const readyState = terminalSocket.value && terminalSocket.value.readyState
  return readyState === 1
}

// 窗口大小变化时调整终端并发送resize消息
const handleResize = () => {
  if (fitAddon.value && term.value) {
    fitAddon.value.fit()
    // 只有在实际窗口大小变化时才发送resize消息
    if (terminalSocket.value?.readyState === WebSocket.OPEN) {
      terminalSocket.value.send(JSON.stringify({
        operate: 'resize',
        cols: term.value.cols,
        rows: term.value.rows
      }))
    }
  }
}

onMounted(() => {
  window.addEventListener('resize', handleResize)
  connect()
})

// 解除挂载前 关闭连接
onBeforeUnmount(() => {
  terminalSocket.value && terminalSocket.value.close()
  window.removeEventListener('resize', handleResize)
  // 清除定时器
  if (resizeTimer) clearTimeout(resizeTimer)
})

</script>

<style scoped>


.webssh-container {
  display: flex;
  height: 100%;
  background-color: #1E1E1E;
  color: #F0F0F0;
  flex: 1;
  overflow: hidden;
  position: relative;
}

.terminal-container {
  height: 90vh;
  width: 100%;
  padding: 0; /* 移除内边距 */
  background-color: #1E1E1E;
  overflow: hidden; /* 防止出现滚动条 */
  flex: 1;
}


:deep(.xterm) {
  padding: 0;
  height: 100%;
  width: 100%;
}

:deep(.xterm-viewport) {
  width: 100% !important;
  background-color: #1E1E1E;
}

:deep(.xterm-screen) {
  width: 100% !important;
}
</style>
